package com.dgut.app.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.dgut.app.param.CollectListParam;
import com.dgut.app.param.CollectParam;
import com.dgut.common.result.OrderDetailResult;
import com.dgut.common.entity.*;
import com.dgut.common.enums.OrderEnum;
import com.dgut.common.enums.StatusEnum;
import com.dgut.common.mapper.*;
import com.dgut.common.param.OrderFormParam;
import com.dgut.app.service.OrderService;
import com.dgut.common.param.OrderListParam;
import com.dgut.common.utils.ApiException;
import com.dgut.common.utils.JwtUtil;
import com.dgut.common.utils.KeyUtil;
import com.dgut.common.utils.PageVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Author zyq
 * @Date 2022/4/13 15:40
 * @Description TODO
 * @Version 1.0
 **/
@Service
@Slf4j
@RequiredArgsConstructor
public class OrderServiceImpl implements OrderService {

    private final CollectionOrderMapper orderMapper;
    private final UserInfoMapper infoMapper;
    private final OrderDetailMapper detailMapper;
    private final WxUserMapper userMapper;
    private final MoneyRecordMapper recordMapper;
    private final ParamMapper paramMapper;
    private final CategoryMapper categoryMapper;
    private final ItemMapper itemMapper;

    @Override
    public void publishOrder(OrderFormParam param, String token) {
        WxUser user = JwtUtil.getUser(token);
        UserInfo info = infoMapper.selectByUserId(user.getId(), StatusEnum.SUCCESS_AUDIT.getState());
        if (info == null) {
            log.error("[OrderServiceImpl - publishOrder]");
            throw new ApiException("请确认是否已进行实名认证");
        }
        CollectionOrder order = new CollectionOrder();
        BeanUtils.copyProperties(param, order);
        order.setEmployerId(user.getId())
                .setEmployerName(info.getName())
                .setState(OrderEnum.WAIT_ACCEPT.getCode())
                .setId(KeyUtil.uniqueKey())
                .setAddress(param.getProvince() + param.getCity() + param.getTown() + param.getDetailAddr());
        orderMapper.insert(order);
    }

    @Override
    public PageVO listOrder(OrderListParam param, String token) {
        WxUser user = JwtUtil.getUser(token);
        IPage<CollectionOrder> page = new Page<CollectionOrder>().setCurrent(param.getPageNum()).setSize(param.getPageSize());
        QueryWrapper<CollectionOrder> wrapper = new QueryWrapper<>();
        wrapper.orderByDesc("create_time");
        if (param.getBeginTime() != null && param.getEndTime() != null) {
            wrapper.between("subscription_time", param.getBeginTime(), param.getEndTime());
        }

        if (param.getState() != null && !Integer.valueOf(-1).equals(param.getState())) {
            wrapper.eq("state", param.getState());
        }

        if (param.getTag() != null && !Integer.valueOf(-1).equals(param.getTag())) {
            if (Integer.valueOf(0).equals(param.getTag())) {
                wrapper.eq("employer_id", user.getId());
            } else {
                wrapper.eq("collector_id", user.getId());
            }
        }

        IPage<CollectionOrder> orderIPage = orderMapper.selectPage(page, wrapper);
        return PageVO.convert(orderIPage);
    }

    @Override
    public OrderDetailResult detail(String id) {
        CollectionOrder collectionOrder = orderMapper.selectById(id);
        if (collectionOrder == null) {
            throw new ApiException("订单信息不存在");
        }
        UserInfo eInfo = infoMapper.selectByUserId(collectionOrder.getEmployerId(), StatusEnum.SUCCESS_AUDIT.getState());
        UserInfo cInfo = infoMapper.selectByUserId(collectionOrder.getCollectorId(), StatusEnum.SUCCESS_AUDIT.getState());

        QueryWrapper<OrderDetail> wrapper = new QueryWrapper<>();
        wrapper.eq("order_id", id);
        List<OrderDetail> orderDetails = detailMapper.selectList(wrapper);

        return OrderDetailResult.builder()
                .order(collectionOrder)
                .employer(eInfo)
                .collector(cInfo)
                .details(orderDetails)
                .build();
    }

    @Override
    public void accept(String id, String token) {
        WxUser user = JwtUtil.getUser(token);
        if (!StatusEnum.COLLECTOR.getState().equals(user.getIdentity())) {
            throw new ApiException("只有回收员可进行接单操作");
        }

        UserInfo info = infoMapper.selectByUserId(user.getId(), StatusEnum.SUCCESS_AUDIT.getState());
        CollectionOrder order = orderMapper.selectById(id);
        if (order == null) {
            throw new ApiException("订单信息不存在");
        }
        if (!OrderEnum.WAIT_ACCEPT.getCode().equals(order.getState())) {
            throw new ApiException("订单状态不正确");
        }

        // TODO 发布者和接单者不能是同一用户

        order.setState(OrderEnum.WAIT_COLLECT.getCode());
        order.setAcceptTime(new Date());
        order.setCollectorId(user.getId());
        order.setCollectorName(info.getName());
        orderMapper.updateById(order);
    }

    @Override
    public void cancel(String id, String token) {
        WxUser user = JwtUtil.getUser(token);
        CollectionOrder order = orderMapper.selectById(id);
        if (order == null) {
            throw new ApiException("订单信息不存在");
        }
        if (order.getEmployerId().compareTo(user.getId()) != 0) {
            throw new ApiException("仅发布者可取消订单");
        }
        if (OrderEnum.WAIT_ACCEPT.getCode().compareTo(order.getState()) != 0) {
            throw new ApiException("订单状态错误");
        }

        order.setState(OrderEnum.CANCELED.getCode());
        order.setFinishTime(new Date());
        orderMapper.updateById(order);
    }

    @Override
    public void cancelAccept(String id, String token) {
        WxUser user = JwtUtil.getUser(token);
        CollectionOrder order = orderMapper.selectById(id);
        if (order == null) {
            throw new ApiException("订单信息不存在");
        }
        if (OrderEnum.WAIT_COLLECT.getCode().compareTo(order.getState()) != 0) {
            throw new ApiException("订单状态错误");
        }
        if (order.getCollectorId().compareTo(user.getId()) != 0) {
            throw new ApiException("仅接单者可取消接单");
        }

        order.setCollectorName(null);
        order.setCollectorId(null);
        order.setAcceptTime(null);
        order.setState(OrderEnum.WAIT_ACCEPT.getCode());
        orderMapper.updateById(order);
    }

    @Override
    @Transactional
    public void collect(CollectParam param, String token) {
        if (param.getDetails() == null || param.getDetails().size() == 0) {
            throw new ApiException("回收物不能为空");
        }

        WxUser user = JwtUtil.getUser(token);
        CollectionOrder order = orderMapper.selectById(param.getId());
        if (order == null) {
            throw new ApiException("订单信息不存在");
        }
        if (order.getCollectorId().compareTo(user.getId()) != 0) {
            throw new ApiException("仅接单者可完成回收");
        }
        if (OrderEnum.WAIT_COLLECT.getCode().compareTo(order.getState()) != 0) {
            throw new ApiException("订单状态错误");
        }

        Map<Integer, Category> categoryMap = categoryMapper.selectList(null).stream().collect(Collectors.toMap(Category::getId, e -> e));
        Map<Integer, Item> itemMap = itemMapper.selectList(null).stream().collect(Collectors.toMap(Item::getId, e -> e));

        // 插入订单详情并统计订单总金额、废品总重量
        int allWeight = 0;
        int allMoney = 0;
        for (CollectListParam detail : param.getDetails()) {
            int amount = detail.getWeight() * itemMap.get(detail.getItemId()).getPrice();
            detailMapper.insert(new OrderDetail()
                    .setOrderId(order.getId())
                    .setCategoryId(detail.getCategoryId())
                    .setCategoryName(categoryMap.get(detail.getCategoryId()).getName())
                    .setItemId(detail.getItemId())
                    .setItemName(itemMap.get(detail.getItemId()).getName())
                    .setWeight(detail.getWeight())
                    .setAmount(amount));
            allWeight += detail.getWeight();
            allMoney += amount;
        }

        // 更新订单总金额、废品总重量、订单状态
        order.setAmount(allMoney);
        order.setTotalWeight(allWeight);
        order.setState(OrderEnum.COLLECTED.getCode());
        orderMapper.updateById(order);
    }

    @Override
    @Transactional
    public void confirm(String id, String token) {
        WxUser user = JwtUtil.getUser(token);
        CollectionOrder order = orderMapper.selectById(id);
        if (order == null) {
            throw new ApiException("订单信息不存在");
        }
        if (order.getEmployerId().compareTo(user.getId()) != 0) {
            throw new ApiException("仅发布者可确认订单");
        }
        if (OrderEnum.COLLECTED.getCode().compareTo(order.getState()) != 0) {
            throw new ApiException("订单状态错误");
        }

        order.setState(OrderEnum.FINISHED.getCode());
        order.setFinishTime(new Date());
        orderMapper.updateById(order);

        Param param = paramMapper.selectById(1);

        // 更新发布者与回收员的金额信息，并添加流水记录
        userMapper.updateMoney(order.getAmount(), order.getEmployerId());
        // 回收员收入
        int collectorIncome = new Double(order.getAmount() * (param.getRate() / 100D)).intValue();
        userMapper.updateMoney(collectorIncome, order.getCollectorId());

        recordMapper.insert(new MoneyRecord()
                .setType(StatusEnum.GARBAGE_INCOME.getState())
                .setUserId(order.getEmployerId())
                .setAmount(order.getAmount()));

        recordMapper.insert(new MoneyRecord()
                .setType(StatusEnum.WORK_INCOME.getState())
                .setUserId(order.getCollectorId())
                .setAmount(collectorIncome));
    }

    @Override
    @Transactional
    public void cancelConfirm(String id, String token) {
        WxUser user = JwtUtil.getUser(token);
        CollectionOrder order = orderMapper.selectById(id);
        if (order == null) {
            throw new ApiException("订单信息不存在");
        }
        if (order.getEmployerId().compareTo(user.getId()) != 0) {
            throw new ApiException("仅发布者可打回订单");
        }
        if (OrderEnum.COLLECTED.getCode().compareTo(order.getState()) != 0) {
            throw new ApiException("订单状态错误");
        }

        // 打回订单，删除订单详情
        QueryWrapper<OrderDetail> wrapper = new QueryWrapper<>();
        wrapper.eq("order_id", order.getId());
        detailMapper.delete(wrapper);

        // 修改订单状态为待回收
        order.setState(OrderEnum.WAIT_COLLECT.getCode());
        order.setTotalWeight(null);
        order.setAmount(null);
        orderMapper.updateById(order);

    }
}
